#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGV_SIZE 32
#define EXIT_CODE 44

int lastcode=0;
int quit=0;
extern char **environ;	
char commandline[LINE_SIZE];
char *argv[ARGV_SIZE];
char pwd[LINE_SIZE];
char myenv[LINE_SIZE];

const char *getusername()
{
	return getenv("USER");
}

const char *gethostname()
{
	return getenv("HOSTNAME");
}

void getpwd()
{
	getcwd(pwd,sizeof(pwd));
}

void interact(char *cline,int size)
{
	getpwd();
	printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getusername(),gethostname(),pwd);
	//scanf("%s",commandline);
	char *s=fgets(cline,size,stdin);
	assert(s);
	(void)s;

	//"abcd\n\0"把\n变为\0
	cline[strlen(cline)-1]='\0';
}

int splistring(char cline[],char *_argv[])
{
	int i=0;
	argv[i++]=strtok(cline,DELIM);
	while(_argv[i++]=strtok(NULL,DELIM));
	return i-1;
}

void NormalExcute(char *_argv[])
{

	pid_t id=fork();
	if(id<0){
		perror("fork");
		return;
	}
	else if(id==0){
		//让子进程执行命令
		execvp(_argv[0],_argv);
		exit(EXIT_CODE);
	}
	else{
		int status=0;
		pid_t rid=waitpid(id,&status,0);
		if(rid==id){
			lastcode=WEXITSTATUS(status);
		}
	}
	
}

int buildCommand(char *_argv[],int _argc)
{

	if(_argc==2&&strcmp(argv[0],"cd")==0)
	{
		chdir(argv[1]);
		getpwd();
		sprintf(getenv("PWD"),"%s",pwd);
		//putenv(argv[1]);
		return 1;
	}
	else if(_argc==2&&strcmp(_argv[0],"export")==0)
	{
		strcpy(myenv,_argv[1]);
		putenv(myenv);
		return 1;
	}
	else if(_argc==2&&strcmp(_argv[0],"echo")==0)
	{
		if(strcmp(argv[1],"$?")==0)
		{
			printf("%d\n",lastcode);
			lastcode=0;
		}
		else if(*_argv[1]=='$')
		{
			char *val=getenv(_argv[1]+1);
			if(val) printf("%s\n",val);
		}
		else
		{
			printf("%s\n",_argv[1]);
		}
		return 1;
	}

	//特殊处理ls
	if(strcmp(_argv[0],"ls")==0)
	{
		_argv[_argc++]="--color";
		_argv[_argc]=NULL;
	}
	return 0;
}

int main()
{

	while(!quit){
		//2.交互问题，获取命令行
		interact(commandline,sizeof(commandline));
		//3.子串分割问题，解释命令行 就是把选项分开获取
		int argc=splistring(commandline,argv);
		if(argc==0) continue;
		
		//4.指令的判断
		//debug
		//for(int i=0;argv[i];i++) printf("[%d]: %s\n",i,argv[i]);
		//内键命令，本质就是一个shell内部的函数
		int n=buildCommand(argv,argc);

		//5.普通命令执行
		if(!n) NormalExcute(argv);
	}
	return 0;
}
